package com.codemonkey.lq.tools;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Pattern;

/**
 * From https://blog.csdn.net/isea533/article/details/77197017
 * @author LQ
 *
 */
public final class MvnBatchDeployer {
	public static void main(String[] args) {
		//uploadFolder("F:\\.m2\\repository");

		// 
		 uploadFolder("C:\\Users\\LQ\\.m2\\repository\\com\\dianping");

		//commandline(args);
	}

	private static void uploadFolder(final String folderFullPath) {
		// 直接指定一个仓库的目录
		deploy(new File(folderFullPath).listFiles());
		EXECUTOR_SERVICE.shutdown();
		try {
			ERROR.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 通过命令行调用时指定目录
	private static void commandline(String[] args) {
		if (checkArgs(args)) {
			File file = new File(args[0]);
			deploy(file.listFiles());
		}
		EXECUTOR_SERVICE.shutdown();
		try {
			ERROR.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * mvn -s F:\.m2\settings.xml
	 * deploy:deploy-file 
	 * -Durl=http://IP:PORT/nexus/content/repositories/thirdpart 
	 * -DrepositoryId=thirdpart
	 * -Dfile=antlr-2.7.2.jar
	 * -DpomFile=antlr-2.7.2.pom
	 * -Dpackaging=jar
	 * -DgeneratePom=false
	 * -Dsources=./path/to/artifact-name-1.0-sources.jar
	 * -Djavadoc=./path/to/artifact-name-1.0-javadoc.jar
	 */
	public static final String BASE_CMD = "cmd /c mvn " + // 可以保证使用 Java 的runtime 执行命令时，可以找到命令。
			"-s C:\\Users\\LQ\\.m2\\settings.xml " + // 参数指定了配置文件的路径（避免多个配置的时候不知道配置那个）。
			"deploy:deploy-file " + // 上传文件的命令
			"-Durl=http://119.97.231.254:803/nexus/content/repositories/releases/ " + // 指定了上传的位置，从nexus中可以找到这个地址。
			"-DrepositoryId=releases " + // 必须和上面指定的地址一致，从nexus仓库配置可以看到这个id，另外上面提到的settings.xml中的用户密码要和这个id匹配。
			"-DgeneratePom=false"; //因为我们会传pom文件，所以禁用自动生成。

	public static final Pattern DATE_PATTERN = Pattern.compile("-[\\d]{8}\\.[\\d]{6}-");

	public static final Runtime CMD = Runtime.getRuntime();

	public static final Writer ERROR;

	public static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(10);

	// 创建了一个文件来记录错误信息，并且提供了一个静态方法方便使用。
	static {
		Writer err = null;
		try {
			err = new OutputStreamWriter(new FileOutputStream("deploy-error.log"), "utf-8");
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
		ERROR = err;
	}

	public static void error(String error) {
		try {
			System.err.println(error);
			ERROR.write(error + "\n");
			ERROR.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 参数校验和提示信息。
	public static boolean checkArgs(String[] args) {
		if (args.length != 1) {
			System.out.println("用法如： java -jar Deploy D:\\some\\path\\");
			return false;
		}
		File file = new File(args[0]);
		if (!file.exists()) {
			System.out.println(args[0] + " 目录不存在!");
			return false;
		}
		if (!file.isDirectory()) {
			System.out.println("必须指定为目录!");
			return false;
		}
		return true;
	}

	// 判断pom文件的packaging 是否为 pom
	public static boolean packingIsPom(File pom) {
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(pom)));
			String line;
			while ((line = reader.readLine()) != null) {
				if (line.trim().indexOf("<packaging>pom</packaging>") != -1) {
					return true;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				reader.close();
			} catch (Exception e) {
			}
		}
		return false;
	}

	// 当为pom类型时，只需要上传pom。
	public static void deployPom(final File pom) {
		EXECUTOR_SERVICE.execute(new Runnable() {
			@Override
			public void run() {
				StringBuffer cmd = new StringBuffer(BASE_CMD);
				// 注意DpomFile和Dfile都指定的pom文件。
				cmd.append(" -DpomFile=").append(pom.getName());
				cmd.append(" -Dfile=").append(pom.getName());
				try {
					final Process proc = CMD.exec(cmd.toString(), null, pom.getParentFile());
					InputStream inputStream = proc.getInputStream();
					InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
					BufferedReader reader = new BufferedReader(inputStreamReader);
					String line;
					StringBuffer logBuffer = new StringBuffer();
					logBuffer.append("\n\n\n=====================================\n");
					while ((line = reader.readLine()) != null) {
						if (line.startsWith("[INFO]") || line.startsWith("Upload")) {
							logBuffer
									.append(Thread.currentThread().getName() + " : " + line + "\n");
						}
					}
					System.out.println(logBuffer);
					int result = proc.waitFor();
					if (result != 0) {
						error("上传失败：" + pom.getAbsolutePath());
					}
				} catch (IOException e) {
					error("上传失败：" + pom.getAbsolutePath());
					e.printStackTrace();
				} catch (InterruptedException e) {
					error("上传失败：" + pom.getAbsolutePath());
					e.printStackTrace();
				}
			}
		});
	}

	// 必须有pom和jar，source和javadoc可选。
	// 当上传的文件包含 jar 时，使用下面的方式。
	public static void deploy(final File pom, final File jar, final File source, final File javadoc) {
		EXECUTOR_SERVICE.execute(new Runnable() {
			@Override
			public void run() {
				StringBuffer cmd = new StringBuffer(BASE_CMD);
				cmd.append(" -DpomFile=").append(pom.getName());
				if (jar != null) {
					//当有bundle类型时，下面的配置可以保证上传的jar包后缀为.jar
					cmd.append(" -Dpackaging=jar -Dfile=").append(jar.getName());
				} else {
					cmd.append(" -Dfile=").append(pom.getName());
				}
				if (source != null) {
					cmd.append(" -Dsources=").append(source.getName());
				}
				if (javadoc != null) {
					cmd.append(" -Djavadoc=").append(javadoc.getName());
				}

				try {
					final Process proc = CMD.exec(cmd.toString(), null, pom.getParentFile());
					InputStream inputStream = proc.getInputStream();
					InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
					BufferedReader reader = new BufferedReader(inputStreamReader);
					String line;
					StringBuffer logBuffer = new StringBuffer();
					logBuffer.append("\n\n\n=====================================\n");
					while ((line = reader.readLine()) != null) {
						if (line.startsWith("[INFO]") || line.startsWith("Upload")) {
							logBuffer
									.append(Thread.currentThread().getName() + " : " + line + "\n");
						}
					}
					System.out.println(logBuffer);
					int result = proc.waitFor();
					if (result != 0) {
						error("上传失败：" + pom.getAbsolutePath());
					}
				} catch (IOException e) {
					error("上传失败：" + pom.getAbsolutePath());
					e.printStackTrace();
				} catch (InterruptedException e) {
					error("上传失败：" + pom.getAbsolutePath());
					e.printStackTrace();
				}
			}
		});
	}

	// 对上面代码封装后的方法，这个方法用于迭代查找包含pom,jar,source和javadoc的目录和文件。
	public static void deploy(File[] files) {
		if (files.length == 0) {
			//ignore
		} else if (files[0].isDirectory()) {
			for (File file : files) {
				if (file.isDirectory()) {
					deploy(file.listFiles());
				}
			}
		} else if (files[0].isFile()) {
			File pom = null;
			File jar = null;
			File source = null;
			File javadoc = null;
			//忽略日期快照版本，如 xxx-mySql-2.2.6-20170714.095105-1.jar
			for (File file : files) {
				String name = file.getName();
				if (DATE_PATTERN.matcher(name).find()) {
					//skip
				} else if (name.endsWith(".pom")) {
					pom = file;
				} else if (name.endsWith("-javadoc.jar")) {
					javadoc = file;
				} else if (name.endsWith("-sources.jar")) {
					source = file;
				} else if (name.endsWith(".jar")) {
					jar = file;
				}
			}
			if (pom != null) {
				if (jar != null) {
					deploy(pom, jar, source, javadoc);
				} else if (packingIsPom(pom)) {
					deployPom(pom);
				}
			}
		}
	}
}
